/* 
 * File:   main.cpp
 * Author: nata
 *
 * Created on March 13, 2012, 3:13 PM
 */

#include <cstdlib>
#include <cstdio>
#include <vector>
#include <cstring>
#include <map>
#include <algorithm>
#include <opencv/cv.h>
#include <opencv/ml.h>
#include <opencv/cxcore.h>
#include <opencv/highgui.h>
#include <opencv/cvaux.h>

#include "Image.h"
#include "Node.h"
#include "BRIC.h"
#include "Renderer.h"
#include "Layout.h"
#include "TreeComparator.h"

using namespace std;

vector<Image*>* image_list;
vector<IplImage*>* solutions;
Renderer* renderer;
BRIC* bric;
int width;
int height;
int alpha;
int beta;
int L;

IplImage* render_solution(vector<Image*> *images) {
    Node* root = bric->createTree(images);
    map<Node*, int>* mapa = new map<Node*, int>();
    bric->mapear(root, mapa);
    return renderer->drawImage(root, mapa);
}

IplImage* render_solution(vector<Image*> *images, Orientation orientation) {
    Node* root = bric->createTree(images);
    map<Node*, int>* mapa = new map<Node*, int>();
    bric->mapear(root, mapa);
    bric->solve(root, orientation);
    return renderer->drawImage(root, mapa);
}

void show_images(vector<IplImage*> *image_list) {
    printf("Mostrando %d imagem(ns)\n", image_list->size());
    printf("Pressione Q para interromper\n");
    bool run = true;
    for(int i = 0; i < image_list->size() && run;) {
        stringstream sstream;
        sstream << i + 1 << " / " << image_list->size();
        string title = sstream.str();
        cvShowImage(title.c_str(), image_list->at(i));
        cvMoveWindow(title.c_str(), 0, 0);
        char c = cvWaitKey(0);
        switch(c) {
            case 'q':
                run = false;
                break;
            case 'b':
                if(i > 0)
                    i -= 1;
                break;
            default:
                i ++;
        }
        cvDestroyWindow(title.c_str());
    }
    printf("Fim\n");
}
void init() {
    image_list = new vector<Image*>();
    solutions = new vector<IplImage*>();
    width = 800;
    height = 600;
    alpha = 1;
    beta = 1;
    L = 5;
    bric = new BRIC(width, height, alpha, beta, L);
    renderer = new Renderer(width, height, alpha, beta);
}

/*
 Code automatic algorithm
 */
void image_populate(vector<Image*>* image_list) {
    image_list->push_back(new Image(800, 600, 1));
    image_list->push_back(new Image(600, 480, 1));
    image_list->push_back(new Image(800, 800, 1));
    image_list->push_back(new Image(800, 600, 1));
    image_list->push_back(new Image(600, 480, 2));
    image_list->push_back(new Image(600, 400, 2));
    image_list->push_back(new Image(600, 800, 2));
    image_list->push_back(new Image(480, 600, 2));
    image_list->push_back(new Image(600, 600, 3));
    image_list->push_back(new Image(600, 480, 2));
    image_list->push_back(new Image(600, 400, 2));
    image_list->push_back(new Image(600, 800, 2));
    image_list->push_back(new Image(480, 600, 2));
    image_list->push_back(new Image(600, 600, 3));
}

void render_solutions(vector<Image*>* imageList, vector<IplImage*>* solutions) {
    vector<Image*>* images = new vector<Image*>();
    for(int i = 0; i < imageList->size(); i++) {
        images->push_back(imageList->at(i));
        solutions->push_back(render_solution(images));
    }
}

void normalRun() {
    image_populate(image_list);
    render_solutions(image_list, solutions);
    show_images(solutions);
}

void double_solutions() {
    image_populate(image_list);
    vector<Image*> images;
    int limit = image_list->size();
    for(int i = 0; i < limit; i++) {
        images.push_back(image_list->at(i));
        solutions->push_back(render_solution(&images, HORIZONTAL));
        solutions->push_back(render_solution(&images, VERTICAL));
    }
    show_images(solutions);
}

void test1() {
    image_populate(image_list);
    Node* root = bric->createTree(image_list);
    Node* leaf = new Node(new Image(800, 600, 1));
    vector<Node*> trees;
    bric->generateTrees(root, root, leaf, &trees);
    sort(trees.begin(), trees.begin() + trees.size(), TreeComparator(bric));
    map<Node*, int> pam;
    bric->mapear(root, &pam);
    solutions->push_back(renderer->drawImage(root, &pam));
    for(int i = 0; i < trees.size(); i++) {
        bric->mapear(trees.at(i), &pam);
        solutions->push_back(renderer->drawImage(trees.at(i), &pam));
    }
    show_images(solutions);
}

void direct_run() {
    image_populate(image_list);
    Node* root = bric->createTree(image_list);
    map<Node*, int> pam;
    bric->mapear(root, &pam);
    solutions->push_back(renderer->drawImage(root, &pam));
    show_images(solutions);
}

/*
 TODO:
 * -Code DAF
 * -Treat memory usage (free unused pointers)
 * -Find a way to safely enumerate terminal nodes
 */
int main(int argc, char** argv) {
    init();
//    normalRun();
    double_solutions();
//    test1();
//    direct_run();
    return 0;
}

